package com.ler.yrmall.ware.service.impl;

import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ler.yrmall.order.api.OrderApi;
import com.ler.yrmall.basic.Result;
import com.ler.yrmall.enums.ErrorCodeEnum;
import com.ler.yrmall.exception.BusinessException;
import com.ler.yrmall.product.api.ProductApi;
import com.ler.yrmall.product.dto.SkuDTO;
import com.ler.yrmall.ware.constant.WareConstant;
import com.ler.yrmall.ware.dto.StockDetailDTO;
import com.ler.yrmall.ware.dto.StockLockedDTO;
import com.ler.yrmall.ware.dto.WareLockDTO;
import com.ler.yrmall.ware.dto.WareOrderItemDTO;
import com.ler.yrmall.ware.entity.WareEntity;
import com.ler.yrmall.ware.entity.WareOrderTaskDetailEntity;
import com.ler.yrmall.ware.entity.WareOrderTaskEntity;
import com.ler.yrmall.ware.entity.WareSkuEntity;
import com.ler.yrmall.ware.form.WareSkuForm;
import com.ler.yrmall.ware.mapper.WareSkuMapper;
import com.ler.yrmall.ware.service.WareOrderTaskDetailService;
import com.ler.yrmall.ware.service.WareOrderTaskService;
import com.ler.yrmall.ware.service.WareService;
import com.ler.yrmall.ware.service.WareSkuService;
import com.ler.yrmall.ware.vo.WareSkuVO;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author leron
 */
@Slf4j
@Service
public class WareSkuServiceImpl extends ServiceImpl<WareSkuMapper, WareSkuEntity> implements WareSkuService {

    @Resource
    private RocketMQTemplate rocketMQTemplate;

    @Resource
    private WareOrderTaskDetailService wareOrderTaskDetailService;

    @Resource
    private WareOrderTaskService orderTaskService;

    @Resource
    private WareService wareService;

    @DubboReference
    private ProductApi productApi;

    @DubboReference
    private OrderApi orderApi;

    @Override
    public IPage<WareSkuVO> find(WareSkuForm request) {
        IPage<WareSkuVO> page = this.baseMapper.find(request.getPage(), request);
        List<Long> skuIds = page.getRecords().stream().map(WareSkuVO::getSkuId).collect(Collectors.toList());
        if (!skuIds.isEmpty()) {
            Result<List<SkuDTO>> skuResponse = productApi.listSkuByIds(skuIds);
            Assert.isTrue(skuResponse.isSuccess(),() -> new BusinessException(ErrorCodeEnum.SKU_FIND_ERROR));
            Map<Long, SkuDTO> skuMap = skuResponse.getData().stream().collect(Collectors.toMap(SkuDTO::getId, Function.identity(),(a,b) -> a));
            page.getRecords().forEach(item -> {
                item.setSkuName(Optional.ofNullable(skuMap.get(item.getSkuId())).map(SkuDTO::getName).orElse(""));
            });
        }
        return page;
    }

    @Override
    public Map<Long, Boolean> hasStockBySkuIds(List<Long> skuIds) {
        Map<Long, Boolean> map = new HashMap<>();
        skuIds.forEach(sku -> {
            Long count = baseMapper.getSkuStock(sku);
            map.put(sku, count != null && count > 0);
        });
        return map;
    }


    @Override
    public void unStockLock(Long skuId, Long wareId, Long taskDetailId, Integer num) {
        this.baseMapper.unStockLock(skuId, taskDetailId, wareId, num);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteWareSku(List<Long> ids) {
        List<WareSkuEntity> wareSkuList = this.listByIds(ids);
        List<Long> wareIds = wareSkuList.stream().map(WareSkuEntity::getWareId).collect(Collectors.toList());
        List<WareEntity> list = wareService.listByIds(wareIds);
        if (!list.isEmpty()) {
            List<WareEntity> collect = list.stream().filter(item -> item.getStatus() == 1).collect(Collectors.toList());
            if (!collect.isEmpty()) {
                throw new BusinessException(ErrorCodeEnum.WARE_SKU_DELETE_BEFORE);
            }
        }
        List<WareSkuEntity> collect = wareSkuList.stream().filter(item -> item.getStockLocked() > 0).collect(Collectors.toList());
        if (!collect.isEmpty()) {
            throw new BusinessException(ErrorCodeEnum.WARE_SKU_DELETE_FAIL);
        }
        this.removeBatchByIds(ids);
    }

    @Override
    public void increment(Long id, Integer skuNum) {
        this.baseMapper.increment(id,skuNum);
    }

    /**
     * 库存自动解锁的场景
     * 1、下订单成功，但是订单过期没有支付系统/用户自动取消
     * 2、下单成功，库存锁定成功，由于订单业务异常导致订单回滚
     *
     * @param wareLock
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean orderLock(WareLockDTO wareLock) {

        //创建工作单
        WareOrderTaskEntity wareOrderTaskEntity = new WareOrderTaskEntity();
        wareOrderTaskEntity.setOrderSn(wareLock.getOrderSn());
        orderTaskService.save(wareOrderTaskEntity);

        //查询所有仓库
        List<WareOrderItemDTO> orders = wareLock.getOrders();
        List<SkuWareHasStock> wareWrapper = orders.stream().map(item -> {
            SkuWareHasStock skuWareHasStock = new SkuWareHasStock();
            skuWareHasStock.setSkuId(item.getSkuId());
            skuWareHasStock.setSkuName(item.getTitle());
            skuWareHasStock.setNum(item.getCount());
            List<Long> wareIds = this.baseMapper.listWareIdHasSkuStock(item.getSkuId());
            skuWareHasStock.setWareId(wareIds);
            return skuWareHasStock;
        }).collect(Collectors.toList());

        for (SkuWareHasStock skuWareHasStock : wareWrapper) {
            if (skuWareHasStock.getWareId() == null || skuWareHasStock.getWareId().size() == 0) {
                throw new BusinessException(skuWareHasStock.getSkuName() + "暂无库存");
            }
            boolean lock = false;
            for (Long wareId : skuWareHasStock.getWareId()) {
                Integer row = this.baseMapper.skuLock(skuWareHasStock.getSkuId(), skuWareHasStock.getNum(), wareId);
                if (row == 1) {
                    //保存订单项
                    WareOrderTaskDetailEntity wareOrderTaskDetailEntity =
                            new WareOrderTaskDetailEntity(null, skuWareHasStock.getSkuId(),
                                    skuWareHasStock.getSkuName(), skuWareHasStock.getNum(), wareOrderTaskEntity.getId(), wareId, 1);
                    wareOrderTaskDetailService.save(wareOrderTaskDetailEntity);
                    StockLockedDTO stockLockedTo = new StockLockedDTO();
                    stockLockedTo.setTaskId(wareOrderTaskEntity.getId());
                    StockDetailDTO stockDetailTo = new StockDetailDTO();
                    BeanUtils.copyProperties(wareOrderTaskDetailEntity, stockDetailTo);
                    stockLockedTo.setDetail(stockDetailTo);
                    Message<StockLockedDTO> message = MessageBuilder.withPayload(stockLockedTo).build();
                    rocketMQTemplate.syncSend(WareConstant.STOCK_LOCK_TOPIC, message, 3000, 3);
                    lock = true;
                    break;
                }
            }
            if (!lock) {
                throw new BusinessException(skuWareHasStock.getSkuName() + "暂无库存");
            }
        }
        return true;
    }

    @Data
    static
    class SkuWareHasStock {

        private Long skuId;

        private String skuName;

        private Integer num;

        private List<Long> wareId;
    }

}